package com.atguigu.gmall.product.service.impl;

import com.atguigu.gmall.product.service.TestService;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * projectName: gmall
 *
 * @author: 陈鹏
 * time: 2022/9/26 15:41 星期一
 * description:
 */
@Service
public class TestServiceImpl implements TestService {

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 测试redis
     */
    @Override
    public void setRedis() {
        // synchronized 只能锁住单一架构

        //锁过期 可能出现锁误删问题 即原线程在删除锁之前锁过期了 原线程可能删除后线程创建的锁 此时需要加判断(引入UUID)

        //setnx 如果不存在则写入
        String uuId = UUID.randomUUID().toString().replace("-", "");

        Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent("lock", uuId,3, TimeUnit.SECONDS);
        if(aBoolean){
            //从redis中获取某个key
            Integer i = (Integer) redisTemplate.opsForValue().get("java0409");
            //判断是否为空
            if(i != null){
                i++;
                //对redis进行写操作
                redisTemplate.opsForValue().set("java0409",i);
            }
            //释放锁  释放锁万一失败 出现死锁问题
            //redisTemplate.delete("lock");

            //判断是否为自己创建的锁 是的话执行删除
            //String redisUUID = (String) redisTemplate.opsForValue().get("lock");
            //if(redisUUID.equals(uuId)){
            //    redisTemplate.delete("lock");
            //}

            //初始化脚本对象
            DefaultRedisScript script = new DefaultRedisScript();
            script.setScriptText("if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end");
            script.setResultType(Long.class);
            //通过LUA脚本释放锁
            redisTemplate.execute(script, Arrays.asList("lock"),uuId);

        }else{
            try{
                Thread.sleep(100);
                //抢锁失败 重试
                setRedis();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    @Autowired
    private RedissonClient redissonClient;
    /**
     * 测试Redisson
     */
    @Override
    public void setByRedisson() {
        RLock lock = redissonClient.getLock("lock");

        try{
            boolean b = lock.tryLock(10, 10, TimeUnit.SECONDS);
            if(b){
                try {
                    //从redis中获取某个key
                    Integer i = (Integer) redisTemplate.opsForValue().get("java0409");
                    //判断是否为空
                    if(i != null){
                        i++;
                        //对redis进行写操作
                        redisTemplate.opsForValue().set("java0409",i);
                    }
                }catch (Exception e1){
                    System.out.println("加锁成功,但是操作出现异常");
                }finally {
                    //释放锁
                    lock.unlock();
                }
            }
        }catch (Exception e){
            System.out.println("获取锁失败");
            e.printStackTrace();
        }
    }
}
